#include <iostream>
#include <vector>
#include <string>
#include <semaphore.h>

using namespace std;

template <typename T>
class RingQueue
{
private:
    void P(sem_t &sem) //++
    {
        sem_wait(&sem);
    }
    void V(sem_t &sem) //--
    {
        sem_post(&sem);
    }
    void Lock(pthread_mutex_t &mutex)
    {
        pthread_mutex_lock(&mutex);
    }
    void UnLock(pthread_mutex_t &mutex)
    {
        pthread_mutex_unlock(&mutex);
    }

public:
    RingQueue(int cap) : _cap(cap), _ring_queue(cap), _productor_step(0), _comsumer_step(0)
    {
        sem_init(&_room_sem, 0, _cap);
        sem_init(&_data_sem, 0, 0);

        pthread_mutex_init(&_product_mutex, nullptr);
        pthread_mutex_init(&_consum_mutex, nullptr);
    }

    // 生产者进行P操作，就是对空间进行--；
    void Enqueue(const T &in)
    {

        // 生产行为
        P(_room_sem);
        Lock(_product_mutex);
        // 一定有空间
        _ring_queue[_productor_step++] = in; // 生产
        _productor_step %= _cap;
        // 数据生成完成，就对数据的个数++
        UnLock(_product_mutex);
        V(_data_sem);
    }
    // 消费者进行V操作，对数据进行++
    void Pop(T *out)
    {

        // 消费行为
        Lock(_consum_mutex);
        P(_data_sem);
        *out = _ring_queue[_comsumer_step++];
        _comsumer_step %= _cap;
        // 消费完成，空间就多出来了
        UnLock(_consum_mutex);
        V(_room_sem);
    }

    ~RingQueue()
    {
        sem_destroy(&_room_sem);
        sem_destroy(&_data_sem);

        pthread_mutex_destroy(&_product_mutex);
        pthread_mutex_destroy(&_consum_mutex);
    }

private:
    vector<T> _ring_queue;
    int _cap; // 环形队列的限

    // 生产者和消费者的下标
    int _productor_step;
    int _comsumer_step;

    // 定义信号量
    sem_t _room_sem; // 生产者Productor关系空间信号量
    sem_t _data_sem; // 消费者Comsumer关系数据信号量

    // 定义锁
    pthread_mutex_t _product_mutex;
    pthread_mutex_t _consum_mutex;
};